/*
 * 亿迅公司源代码，版权归亿迅公司所有。 项目名称 : bnet_process 创建日期 : Apr 30, 2009 修改历史 : 1. [Apr 30,
 * 2009]创建文件 by zhoujinhuang
 */
package cn.eshore.bnet.bpm.service.impl;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.db.GraphSession;
import org.jbpm.graph.def.Node;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.Comment;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;
import org.jbpm.taskmgmt.exe.TaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springmodules.workflow.jbpm31.JbpmTemplate;

import cn.eshore.bnet.bpm.Constants;
import cn.eshore.bnet.bpm.dto.NodeInstanceDTO;
import cn.eshore.bnet.bpm.dto.ProcessInstanceDTO;
import cn.eshore.bnet.bpm.dto.TaskInstanceDTO;
import cn.eshore.bnet.bpm.dto.TaskResult;
import cn.eshore.bnet.bpm.dto.ext.ProcessParam;
import cn.eshore.bnet.bpm.service.ProcessException;
import cn.eshore.bnet.bpm.service.ProcessService;

@Component("processService")
@Transactional
public class ProcessServiceImpl implements ProcessService {
    static Log LOG = LogFactory.getLog(ProcessServiceImpl.class);

    @Autowired
    JbpmTemplate jbpmTemplate;

    @Autowired
    JbpmConfiguration jbpmConfiguration;

    public JbpmConfiguration getJbpmConfiguration() {
        return jbpmConfiguration;
    }

    public void setJbpmConfiguration(JbpmConfiguration jbpmConfiguration) {
        this.jbpmConfiguration = jbpmConfiguration;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#startProcess(java.lang.String,
     *      java.util.List, java.lang.String)
     */
    @Transactional
    public long startProcess(String processName,
            List<ProcessParam> processParams, String businessKey)
            throws ProcessException {

        ProcessInstance processInstance = null;
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        try {
            GraphSession graphSession = jbpmContext.getGraphSession();
            ProcessDefinition processDefinition = graphSession
                    .findLatestProcessDefinition(processName);
            Map<String, Object> variables = createParamsMap(processParams);
            LOG.debug("processDefinitionId  " + processDefinition.getId());
            processInstance = processDefinition.createProcessInstance(
                    variables,
                    businessKey);
            processInstance.signal();
        } catch (Exception e) {
            throw new ProcessException(e.getMessage(), e);
        } finally {
            jbpmContext.close();
        }

        return processInstance.getId();
    }

    /**
     * @see cn.eshore.bnet.bpm.service.ProcessService#getTaskList(java.lang.String)
     */
    @SuppressWarnings("unchecked")
    public List<TaskInstanceDTO> getTaskList(String actorId) {
        List<TaskInstance> taskList = jbpmTemplate.findTaskInstances(actorId);
        LinkedList<TaskInstanceDTO> taskInstanceDTOs = new LinkedList<TaskInstanceDTO>();
        for (Iterator iterator = taskList.iterator(); iterator.hasNext();) {
            TaskInstance taskInstance = (TaskInstance) iterator.next();
            TaskInstanceDTO taskInstanceDTO = new TaskInstanceDTO();
            taskInstanceDTO.setActorId(taskInstance.getActorId());
            taskInstanceDTO.setBlocking(taskInstance.isBlocking());
            taskInstanceDTO.setCancelled(taskInstance.isCancelled());
            taskInstanceDTO.setCreate(taskInstance.getCreate());
            taskInstanceDTO.setDescription(taskInstance.getDescription());
            taskInstanceDTO.setDueDate(taskInstance.getDueDate());
            taskInstanceDTO.setEnd(taskInstance.getEnd());
            taskInstanceDTO.setId(taskInstance.getId());
            taskInstanceDTO.setName(taskInstance.getName());
            taskInstanceDTO.setOpen(taskInstance.isOpen());
            taskInstanceDTO.setSignalling(taskInstance.isSignalling());
            taskInstanceDTO.setStart(taskInstance.getStart());
            taskInstanceDTO.setSuspended(taskInstance.isSuspended());
            taskInstanceDTO.setProcessInstanceId(taskInstance.getId());
            taskInstanceDTOs.add(taskInstanceDTO);

        }
        return taskInstanceDTOs;
    }

    /**
     * 处理任务,并推进流程
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#completeTask(String )
     */
    public void completeTask(TaskResult taskResult) {
        LOG.debug("completeTask called." + taskResult.getTaskInstanceId());
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        TaskInstance taskInstance = jbpmContext.getTaskInstance(taskResult
                .getTaskInstanceId());
        Comment comment = new Comment(taskResult.getActorId(), taskResult
                .getMessage());
        taskInstance.start();
        taskInstance.addComment(comment);
        taskInstance.setVariableLocally(Constants.RESULT_CODE, taskResult
                .getResultCode());
        taskInstance.end();
        jbpmContext.close();
    }

    // public void completeTask(final TaskResult taskResult) {
    // LOG.debug("completeTask called." + taskResult.getTaskInstanceId());
    //
    // jbpmTemplate.execute(new JbpmCallback() {
    // public Object doInJbpm(JbpmContext jbpmContext)
    // throws JbpmException {
    // TaskInstance taskInstance = jbpmContext
    // .getTaskInstance(taskResult.getTaskInstanceId());
    // Comment comment = new Comment(taskResult.getActorId(),
    // taskResult.getMessage());
    // taskInstance.start();
    // taskInstance.addComment(comment);
    // taskInstance.setVariableLocally(
    // Constants.RESULT_CODE,
    // taskResult.getResultCode());
    // taskInstance.end();
    // System.out.println("jbpmContext " + jbpmContext);
    // System.out.println("jbpmContext getTransaction"
    // + jbpmContext.getSession().getTransaction());
    // return null;
    // }
    // });
    // }

    /**
     * 查询流程实例
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#getProcessInstance(long)
     */
    public ProcessInstanceDTO getProcessInstance(long processInstanceId) {
        ProcessInstance processInstance = jbpmTemplate
                .findProcessInstance(processInstanceId);
        ProcessInstanceDTO processInstanceDTO = new ProcessInstanceDTO(
                processInstance);
        return processInstanceDTO;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#signal(long)
     */
    public void resumeToken(long processInstanceId) {
        ProcessInstance processInstance = jbpmTemplate
                .findProcessInstance(processInstanceId);
        final Token rootToken = processInstance.getRootToken();
        LOG.info("resumeToken :" + rootToken.getId());
        rootToken.resume();
        // signal(jbpmTemplate.findProcessInstance(processInstanceId));
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#signal(long)
     */
    public void signal(long processInstanceId) {
        jbpmTemplate
                .signal(jbpmTemplate.findProcessInstance(processInstanceId));
    }

    @SuppressWarnings("unchecked")
    public void updateVar(long processInstanceId,
            List<ProcessParam> processParams) {
        ProcessInstance processInstance = jbpmTemplate
                .findProcessInstance(processInstanceId);
        ContextInstance contextInstance = processInstance.getContextInstance();
        Map<String, Object> variables = createParamsMap(processParams);
        contextInstance.getVariables().putAll(variables);
    }

    /**
     * //TODO 添加方法功能描述
     * 
     * @param processParams
     * @return
     */
    private Map<String, Object> createParamsMap(List<ProcessParam> processParams) {
        Map<String, Object> variables = new HashMap<String, Object>();
        for (ProcessParam processParam : processParams) {
            if (processParam.isValidate()) {
                variables.put(processParam.getKey(), processParam.getValue());
            } else {
                LOG
                        .warn("processParam is invalidate ,"
                                + processParam.getKey());
            }

        }
        return variables;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#deploy(java.lang.String)
     */
    public void deploy(String processDefinitionXml) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        try {
            GraphSession graphSession = jbpmContext.getGraphSession();
            ProcessDefinition processDefinition = ProcessDefinition
                    .parseXmlString(processDefinitionXml);
            graphSession.deployProcessDefinition(processDefinition);
        } finally {
            jbpmContext.close();
        }
    }

    /**
     * //TODO 增加通过文件名获取版本信息版本
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#deploy()
     */
    public void deployAll() {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        try {
            File processDefPath = new File(Constants.PROCESS_DEF_PATH);
            File[] processDefFiles = processDefPath.listFiles();
            GraphSession graphSession = jbpmContext.getGraphSession();
            LOG.info("loading process_definition from :"
                    + processDefPath.getAbsolutePath());
            if (processDefFiles == null) {
                LOG.info("Constants.PROCESS_DEF_PATH error ,"
                        + Constants.PROCESS_DEF_PATH);
                return;
            }
            for (File processDefFile : processDefFiles) {
                if (processDefFile.isFile()) {
                    FileReader fileReader = new FileReader(processDefFile);
                    try {
                        ProcessDefinition processDefinition = ProcessDefinition
                                .parseXmlReader(fileReader);
                        graphSession.saveProcessDefinition(processDefinition);
                        graphSession.deployProcessDefinition(processDefinition);
                    } catch (Exception e) {
                        LOG.error("deploy process failed"
                                + processDefFile.getAbsolutePath(), e);
                    } finally {
                        fileReader.close();
                    }
                }
            }
        } catch (Exception e) {
            LOG.error("deploy process failed", e);
        } finally {
            jbpmContext.close();
        }
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#getProcessParam(long,
     *      java.util.List)
     */
    public List<ProcessParam> getProcessParams(long processInstanceId,
            List<String> paramNames) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        ProcessInstance processInstance = jbpmContext
                .getProcessInstance(processInstanceId);
        List<ProcessParam> paramList = new ArrayList<ProcessParam>();
        for (String name : paramNames) {
            Object variable = processInstance.getContextInstance().getVariable(
                    name);
            paramList.add(new ProcessParam(name, variable));
        }

        Map<String, Object> variables = processInstance.getContextInstance()
                .getVariables();
        Set<String> keySet = variables.keySet();
        for (String key : keySet) {
            Object object = variables.get(key);
            System.out.println(key + "  -- " + object);
        }

        return paramList;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#getLocalParams(long,
     *      java.util.List)
     */
    @Override
    public List<ProcessParam> getLocalParams(long tokenId,
            List<String> paramNames) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        Token token = jbpmContext.getToken(tokenId);
        ContextInstance contextInstance = token.getProcessInstance()
                .getContextInstance();
        List<ProcessParam> paramList = new ArrayList<ProcessParam>();
        for (String name : paramNames) {
            Object variable = contextInstance.getLocalVariable(name, token);
            paramList.add(new ProcessParam(name, variable));
        }
        return paramList;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#getTaskParams(long,
     *      java.util.List)
     */
    @Override
    public List<ProcessParam> getTaskParams(long taskInstanceId,
            List<String> paramNames) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        TaskInstance taskInstance = jbpmContext.getTaskInstance(taskInstanceId);
        List<ProcessParam> paramList = new ArrayList<ProcessParam>();
        for (String name : paramNames) {
            Object variable = taskInstance.getVariable(name);
            paramList.add(new ProcessParam(name, variable));
        }

        Map<String, Object> variables = taskInstance.getProcessInstance()
                .getContextInstance().getVariables();
        Set<String> keySet = variables.keySet();
        for (String key : keySet) {
            Object object = variables.get(key);
            System.out.println(key + "  -- " + object);
        }

        return paramList;
    }

    /**
     * //TODO 添加override说明
     * 
     * @see cn.eshore.bnet.bpm.service.ProcessService#getCurrentNodeInstance(long)
     */
    @Override
    public NodeInstanceDTO getCurrentNodeInstance(long processInstanceId) {

        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        ProcessInstance processInstance = jbpmContext
                .getProcessInstance(processInstanceId);
        final NodeInstanceDTO nodeInstance = new NodeInstanceDTO();
        final Node node = processInstance.getRootToken().getNode();
        nodeInstance.setName(node.getName());
        nodeInstance
                .setEnterTime(processInstance.getRootToken().getNodeEnter());
        return nodeInstance;
    }

    /**
     * 停止流程
     * 
     * @param processInstanceId
     */
    public void endProcessInstance(long processInstanceId) {
        JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
        ProcessInstance processInstance = jbpmContext
                .getProcessInstance(processInstanceId);
        processInstance.suspend();
        processInstance.end();
        jbpmContext.close();
    }

    /**
     * 获取流程的所有流程实例
     * 
     * @param processDefinitionId
     * @return
     */
    public List<ProcessInstanceDTO> findProcessInstances(
            long processDefinitionId) {
        GraphSession graphSession = jbpmTemplate.getJbpmConfiguration()
                .createJbpmContext().getGraphSession();
        List<ProcessInstance> processInstances = graphSession
                .findProcessInstances(processDefinitionId);
        List<ProcessInstanceDTO> processInstanceDTOs = new ArrayList<ProcessInstanceDTO>();
        for (ProcessInstance processInstance : processInstances) {
            ProcessInstanceDTO processInstanceDTO = new ProcessInstanceDTO(
                    processInstance);
            processInstanceDTOs.add(processInstanceDTO);
        }
        return processInstanceDTOs;
    }

    /**
     * @see cn.eshore.bnet.bpm.service.ProcessService#findProcessInstances(java.lang.String)
     */
    public List<ProcessInstanceDTO> findProcessInstances(String processName) {
        GraphSession graphSession = jbpmTemplate.getJbpmConfiguration()
                .createJbpmContext().getGraphSession();
        List<ProcessDefinition> processDefinitionVersions = graphSession
                .findAllProcessDefinitionVersions(processName);
        List<ProcessInstanceDTO> processInstanceDTOs = new ArrayList<ProcessInstanceDTO>();
        for (ProcessDefinition processDefinition : processDefinitionVersions) {
            List<ProcessInstance> processInstances = graphSession
                    .findProcessInstances(processDefinition.getId());
            for (ProcessInstance processInstance : processInstances) {
                ProcessInstanceDTO processInstanceDTO = new ProcessInstanceDTO(
                        processInstance);
                processInstanceDTOs.add(processInstanceDTO);
            }
        }
        return processInstanceDTOs;
    }

}
